%==========================================================================
%=  This file is part of the Sound Restoration Project
%=  (c) Copyright Industrial Mathematics Institute
%=                University of South Carolina, Department of Mathematics
%=  ALL RIGHTS RESERVED
%=
%=  Author: Borislav Karaivanov
%==========================================================================

%==========================================================================
% List of the files on which this procedure depends:
%
% combine2DArraysFromFiles.m
% extractSoundSignals.m
% getSizeOf2DArrayFromFile.m
% readImageByIndex.m
% readImageFile.m
% readdpx.m
% read2DArrayFromFile.m
% setLogWritingFunctHandle.m
% write2DArrayToFile.m
% writeToLogFile.m
%
% image processing toolbox
%
%==========================================================================

%==========================================================================
% The function "getAllSoundSignals" extracts a fixed number of sound
% signals from each image in a specified collection. Each sound signal
% corresponds to a specified pair of vertical sound track bounds. Those
% signals are written to different text files - one file for each pair of
% sound track bounds.
% INPUT: "readFramesFunctHandle" is a handle to a function capable of
% reading any range of frames from a preset source.
% "frameRange" is a single integer or a row vector of two integers
% specifying the index of a single frame or a range of frames to be read
% from a preset source.
% "soundBoundsArr" is a 2D array with two columns specifying the left and
% right vertical bounds of the sound track band in number of pixels. Each
% row corresponds to a pair of left and right bounds. It is expected that 
% 1 <= soundBoundsArr(k, 1) <= soundBoundsArr(k, 2) <= imageWidth for each
% valid value of k.
% "numPerBatch" is an optional integer specifying the number of image files
% to be processed in a batch and have the sound signals extracted from them
% written to the same text file.
% "scratchFileNamePrefix" is an optional string specifying the common
% prefix in the names of all intermediate output files (including a full
% directory path).
% "waitbarStruct" is an optional parameter specifying a structure of
% parameters used to set a waitbar. Those parameters are a waitbar handle,
% a starting position on the waitbar (a number between 0 and 1), a relative
% length along the waitbar (a number between 0 and (1 - starting position),
% an initial value for a counter that counts the events whose progress is
% being illustrated by the waitbar, and a total reflecting the total number
% of events of the said kind.
% "writeToLogFunctHandle" is an optional function handle which writes to a
% fixed log text file if keeping a log is requested, or does nothing
% otherwise.
% OUTPUT: "outFileNameCellArr" returns a cell array with as many rows as
% there are different batches of frames, and as many columns as there are
% different pairs of sound track bounds. Each cell holds the name of a text
% files (including a full directory path) where all sound signals extracted
% from the images are written. An empty cell indicates failure to write the
% corresponding text file.
% "allSignalsCellArr" returns a cell array with as many rows as there are
% different batches of frames, and as many columns as there are different
% pairs of sound track bounds. Each cell holds a 2D array whose columns are
% the sound signals extracted from the frames in the current batch.
%==========================================================================
function [outFileNameCellArr, allSignalsCellArr] = ...
    getAllSoundSignals(readFramesFunctHandle, frameRange, soundBoundsArr, ...
    numPerBatch, scratchFileNamePrefix, waitbarStruct, writeToLogFunctHandle)

if (nargin < 4)
    numPerBatch = 200;
end
if (nargin < 5)
    scratchFileNamePrefix = 'rawSound';
end
if (nargin < 7)
    writeToLogFunctHandle = @(x) '';
end
% Specify that color frames are to be processed as grayscale images.
doConvertToGray = true;

% Read in the first frame.
frameArr = readFramesFunctHandle(frameRange(1), doConvertToGray);

% Get the length of the sound signals.
soundLength = size(frameArr, 1);
% Get the number of pairs of sound bounds to be used.
numPairsOfBounds = size(soundBoundsArr, 1);

% % Allocate memory for the names of the output files where each extracted
% % combined sound signals is to be saved.
% outFileNameCellArr = cell(numPairsOfBounds, 1);

% Determine the number of temporary output files.
numFiles = double(frameRange(end) - frameRange(1) + 1);
numBatches = ceil(numFiles/numPerBatch);

% Allocate a cell array whose cells are to store the names of the temporary
% files where each portion of extracted sound signals will be saved.
outFileNameCellArr = cell(numBatches, numPairsOfBounds);
% Allocate a cell array whose cells are to store the portion of extracted
% sound signals for the different pairs of sound track bounds and the
% different batches of frames.
allSignalsCellArr = cell(numBatches, numPairsOfBounds);

% Split the allotted waitbar length among all batches.
if (exist('waitbarStruct', 'var') == 1)
    localWaitbarStruct = waitbarStruct;
    localWaitbarStruct.length = (waitbarStruct.length)/numBatches;
    if isempty(localWaitbarStruct.total)
        localWaitbarStruct.total = numFiles;
    end
end

% Process the batches of input files.
for batchInd = 1:numBatches
    
    % Extract the sound signals from the current portion of frames and
    % write them to text files - one file for each pair of sound track
    % bounds.
    [outFileNameCellColumn, allSignalsCellColumn] = extractSoundSignals(readFramesFunctHandle, ...
        [frameRange(1) + (batchInd - 1)*numPerBatch, min(frameRange(1) + batchInd*numPerBatch - 1, frameRange(end))], ...
        soundLength, soundBoundsArr, scratchFileNamePrefix, ...
        localWaitbarStruct, writeToLogFunctHandle);
    
    outFileNameCellArr(batchInd, :) = outFileNameCellColumn;
    allSignalsCellArr(batchInd, :) = allSignalsCellColumn;
    
    % Increment the starting position on each iteration.
    if getappdata(localWaitbarStruct.handle, 'canceling')
        return;
    end
    if (exist('waitbarStruct', 'var') == 1)
        localWaitbarStruct.start = localWaitbarStruct.start + localWaitbarStruct.length;
        localWaitbarStruct.first = localWaitbarStruct.first + numPerBatch;
    end
    
    fprintf(1, 'File %d out of %d is done.\n', min(batchInd*numPerBatch, numFiles), numFiles);
end

% % For each pair of sound bounds combine the corresponding text files.
% for pairInd = 1:numPairsOfBounds
%     % Combine the text files corresponding to the different batches into a
%     % single text file with the same format.
%     outFileNameCellArr{pairInd} = combine2DArraysFromFiles(tempFileNameCellArr(:, pairInd));
%     
%     % If the combined file was successfully written, then delete the
%     % individual files whose names differ from that of the combined file.
%     if (isempty(outFileNameCellArr{pairInd}) == false)
%         for batchInd = 1:numBatches
%             if (strcmpi(outFileNameCellArr{pairInd}, tempFileNameCellArr{batchInd, pairInd}) == false)
%                 delete(tempFileNameCellArr{batchInd, pairInd});
%             end
%         end
%     end
% end


% Write info to a log file.
writeToLogFunctHandle(['number of image rows: ' num2str(soundLength)]);
writeToLogFunctHandle(['number of image columns: ' num2str(size(frameArr, 2))]);
writeToLogFunctHandle(['signal length: ' num2str(soundLength)]);
writeToLogFunctHandle(['number of files per batch: ' num2str(numPerBatch)]);
writeToLogFunctHandle(['number of batches: ' num2str(numBatches)]);
writeToLogFunctHandle(['number of pairs of sound bounds: ' num2str(numPairsOfBounds)]);

return;
% end of the function "getAllSoundSignals"
